package ncme.auto.framework.core.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import ncme.auto.framework.core.exceptions.AutoException;
import ncme.auto.framework.core.exceptions.ExceptionEnum;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author sjh
 * @Description
 * @create 2022/2/11 14:24
 */
public class BeanUtil {

    public static Map<String, Object> mapBeanToMap(Object object) {
        return JSONObject.parseObject(JSON.toJSONString(object));
    }

    /**
     * 获取该类的第n个泛型
     *
     * @param beanClass 类
     * @param index     泛型索引
     * @return 泛型类型
     */
    public static Class<?> getBeanGenericClassOfIndex(Class<?> beanClass, Integer index) {
        Type type = beanClass.getGenericSuperclass();
        if (type instanceof ParameterizedType) {
            ParameterizedType parameterizedType_This = (ParameterizedType) type;
            Type entityType = parameterizedType_This.getActualTypeArguments()[index];
            return (Class<?>) entityType;
        }
        return Object.class;
    }

    /**
     * 获取对象的字段值
     *
     * @param entity    实体对象
     * @param fieldName 字段名
     * @return 字段值
     */
    public static Object getFieldValue(Object entity, String fieldName) {
        try {
            if (entity instanceof HashMap) {

                return mapBeanToMap(entity).get(fieldName);
            } else {
                Field idField = entity.getClass().getDeclaredField(fieldName);
                idField.setAccessible(true);
                return idField.get(entity);
            }
        } catch (IllegalAccessException | NoSuchFieldException e) {
            throw new AutoException(ExceptionEnum.UTIL_ERROR, "实体" + entity.toString() + "获取" + fieldName + "失败");
        }
    }

    public static Integer getFieldInteger(Object entity, String fieldName) {
        try {
            return Integer.parseInt(getFieldValue(entity, fieldName).toString());
        } catch (Exception e) {
            throw new AutoException(ExceptionEnum.UTIL_ERROR, "字段转换integer失败");
        }
    }

    /**
     * 设置对象的字段值
     *
     * @param entity    实体对象
     * @param fieldName 字段名
     * @param value     字段值
     */
    public static void setFieldValue(Object entity, String fieldName, Object value) {
        try {

            if (entity instanceof HashMap) {
                mapBeanToMap(entity).put(fieldName, value);
            } else {
                Field field = entity.getClass().getDeclaredField(fieldName);
                field.setAccessible(true);
                field.set(entity, value);
            }
        } catch (NoSuchFieldException | IllegalAccessException e) {
            throw new AutoException(ExceptionEnum.UTIL_ERROR);
        }
    }

    /**
     * 对象List转List<map>
     *
     * @param beans         对象
     * @param excludeFields 需排除的键值
     * @return map
     */
    public static List<Map<String, Object>> beansToMaps(List<?> beans, List<String> excludeFields, boolean removeNull) {
        try {
            List<Map<String, Object>> maps = new ArrayList<>();
            for (Object bean : beans) {
                maps.add(beanToMap(bean, excludeFields, removeNull));
            }
            return maps;
        } catch (Exception e) {
            throw new AutoException(ExceptionEnum.UTIL_ERROR, "@beansToMaps");
        }
    }

    /**
     * 对象转map
     *
     * @param bean          对象
     * @param excludeFields 需排除的键值
     * @return map
     */
    public static Map<String, Object> beanToMap(Object bean, List<String> excludeFields, boolean removeNull) {
        try {
            Map<String, Object> map = new HashMap<>();
            if (excludeFields == null) excludeFields = new ArrayList<>();
            if (bean instanceof HashMap) {
                Map<String, Object> beanMap = mapBeanToMap(bean);
                for (String key : beanMap.keySet()) {
                    Object value = beanMap.get(key);
                    if (!excludeFields.contains(key) && (value != null || !removeNull))
                        map.put(key, value);
                }
            } else {
                Field[] declaredFields = bean.getClass().getDeclaredFields();
                for (Field field : declaredFields) {
                    Object fieldValue = getFieldValue(bean, field.getName());
                    if (!excludeFields.contains(field.getName()) && (fieldValue != null || !removeNull))
                        map.put(field.getName(), fieldValue);
                }
            }
            return map;
        } catch (Exception e) {
            throw new AutoException(ExceptionEnum.UTIL_ERROR, "@beanToMap");
        }
    }

    /**
     * 获取对象中包含某注解的字段list
     *
     * @param annotationClass 注解类型
     * @param entityClass     对象类型
     * @param <T>             对象类型
     * @return 包含某注解的字段list
     */
    public static <T extends Annotation> List<Field> getFieldsWithAnnotation(Class<T> annotationClass, Class<?> entityClass) {
        List<Field> requiredFields = new ArrayList<>();
        Field[] declaredFields = entityClass.getDeclaredFields();
        for (Field field : declaredFields) {
            if (annotationClass == null) requiredFields.add(field);
            else if (field.getDeclaredAnnotation(annotationClass) != null) requiredFields.add(field);
        }
        return requiredFields;
    }

    /**
     * 获取对象中包含某注解的字段名list
     *
     * @param annotationClass 注解类型
     * @param entityClass     对象类型
     * @param <T>             对象类型
     * @return 包含某注解的字段list
     */
    public static <T extends Annotation> List<String> getFieldNamesWithAnnotation(Class<T> annotationClass, Class<?> entityClass) {
        List<String> requiredFields = new ArrayList<>();
        List<Field> fieldsWithAnnotation = getFieldsWithAnnotation(annotationClass, entityClass);
        fieldsWithAnnotation.forEach(field -> requiredFields.add(field.getName()));
        return requiredFields;
    }

}
